#ifndef UDP_SERVER_HPP__
#define UDP_SERVER_HPP__

#include <iostream>
#include <string.h>
#include <strings.h>
#include <error.h>

#include "Common.hpp"
#include "inetAddr.hpp"
#include "Log.hpp"

// 封装版本不需要
// std::string gdefaultip = "127.0.0.1"; // 本地环回IP //本地通信或代码测试就用这个IP
uint16_t gdefaultport = 8080; // 尽量选用没人用的端口号
int gdefaultsockfd = -1;
using namespace LogModule;

class UdpServer
{
public:
    UdpServer(uint16_t port = gdefaultport)
        : _sockfd(gdefaultsockfd), _port(port), _addr(port), _isrunning(false)
    {
    }
    void Init()
    {

        // 1.创建socket套接字
        // 第一个参数网络通信,第二个参数是数据报,Udp协议,第三个参数传0即可
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(Loglevel::FATAL) << "socket" << strerror(errno);
            Die((int)Code::SOCKETERROR);
        }
        LOG(Loglevel::INFO) << "socket success";
        /*
        // 2.填充网络信息并bind绑定
        // 这里只是填充网络信息,bind才是设置进内核
        struct sockaddr_in local;
        bzero(&local, sizeof(local));                       // 将local全置为0,确定性
        local.sin_family = AF_INET;                         // 必须和套接字的一样
        local.sin_port = htons(_port);                      // 设置进内核的port和ip是要发送到网络中的,port要从本地序列转化为网络序列
        local.sin_addr.s_addr = inet_addr(_ip.c_str());     // ip要从string转化为4bytes,还要是网络序列
        local.sin_addr.s_addr=INADDR_ANY;
        */
        // int n = bind(_sockfd, CONV(&local), sizeof(local)); // 一定要注意这里的类型转化
        int n = bind(_sockfd, _addr.NetAddr(), _addr.NetAddrLen());
        if (n < 0)
        {
            LOG(Loglevel::FATAL) << "bind" << strerror(errno);
            Die((int)Code::BINDERROR);
        }
        LOG(Loglevel::INFO) << "bind success";
    }
    void Start()
    {
        _isrunning = true;
        while (true) // 服务器运行起来就不会停止
        {
            // 收到客户端发的信息,将客户端的信息发回去
            char inbuffer[1024];
            struct sockaddr_in peer;      // 必须要有,用来保存谁发来的信息
            socklen_t len = sizeof(peer); //-1预留一个空位给\0
            int n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&peer), &len);
            if (n > 0)
            {
                // 发消息方的ip地址和端口号
                InetAddr cli(peer);
                // 构建要发回去的信息
                inbuffer[n] = 0;
                LOG(Loglevel::DEBUG) << "Client" << cli.Ip() << ":" << std::to_string(cli.Port()) << "says#" << inbuffer;
                std::string echo_string = "echo#";
                echo_string += inbuffer;
                sendto(_sockfd, echo_string.c_str(), sizeof(echo_string), 0, CONV(&peer), len);
            }
        }
        _isrunning = false;
    }
    ~UdpServer()
    {
        if (_sockfd > gdefaultsockfd)
            ::close(_sockfd);
    }

private:
    int _sockfd;
    InetAddr _addr;
    // std::string _ip;
    uint16_t _port;
    bool _isrunning;
};
#endif